<?

class DQ{
    public  $db, 
            $tables, 
            $useindex,
            $fields = "*", 
            $leftjoin, 
            $where, 
            $limit, 
            $offset, 
            $order,
            $group,
            $default_return_class = "Core_Record"
            ;
    public static $default_instance;
    
    
    public function __construct(){
        
    }
    
    public static function __callstatic($method, $param){
        echo "Метод $method не определен";
    }

    
    static public function getInstance(){
        if(!self::$default_instance) self::$default_instance = new self();
        return self::$default_instance;
    }
    
    static public function i(){
        return self::getInstance();
    }

    static public function clear(){
        self::$default_instance = new self();
        return self::$default_instance;
    }
    
    //синоним tables()
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function from($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self))
        	return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->tables;
        if ($value instanceof Core_Record){ 
            $this->default_return_class = get_class($value);
            $value = $value->getFullTableName();
        }
        
        $this->tables = $value;
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function tables($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function fields($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }
    
    public function useindex($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }


    /**
    * Синоним метода fields 
    * 
    * @param mixed $value
    * @return DQ
    */
    public function select($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->fields;
        $this->fields = $value;
        return $this;
    }

    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function leftjoin($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function where($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function and_($value, $key = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if(empty($this->where))     $this->where = array();
        if(is_string($this->where)) $this->where = array($this->where);
        if(is_array($this->where)){
            if($key === null) 
                $this->where[] = $value;
            else
                $this->where[$key] = $value;    
        }
        return $this;
    }
    
    public function andSafe($condition, $value){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if(empty($this->where))     $this->where = array();
        if(is_string($this->where)) $this->where = array($this->where);
        if(count($params) > 2) $value = array_slice($params, 1);
        if(!is_array($value)) $value = array($value);
        $chars_array = str_split($condition);
        $index = 0;
        foreach($chars_array as $key=>$one) // заменяем символ ? на значение из массива 
            if($one == '?' && isset($value[$index])) $chars_array[$key] = "'".mysql_real_escape_string($value[$index++])."'";
        $this->where[] = join('', $chars_array);
        return $this;
    }
    
    public function andIn($field, $values){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if(empty($this->where))     $this->where = array();
        foreach($values as $key => $val) $values[$key] = mysql_real_escape_string($val);
        if(!empty($values))
            $this->where[] = $field." in ('".join("','", $values)."')";
        else 
            $this->where[] = "0";
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function limit($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = (int)$value;
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function offset($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = (int)$value;
        return $this;
    }
    
    /**
    * put your comment there...
    * 
    * @param mixed $value
    * @return DQ
    */
    public function order($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }
    
    public function group($value = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if($value === null) return $this->{__FUNCTION__};
        $this->{__FUNCTION__} = $value;
        return $this;
    }
    
    public function rows($simplify = false){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        $sql = $this->toSelectSql();
        Database::query($sql);
        $rows = Database::FetchAll($sql);
        if($simplify) Arr::arraySimplify($rows);
        return $rows;
    }
    
    public function row($simplify = false){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        $sql = $this->toSelectSql();
        Database::query($sql);
        $row = Database::fetchRow();
        if($simplify) Arr::arraySimplify($row);
        return $row;
    }
    
    public function column($column_name = 0){
        $rows = $this->rows();
        if(empty($rows)) return array();
        $ret = array();
        if(is_numeric($column_name)){
            $columns = array_keys($rows[0]);
            $column_name = $columns[$column_name];
        }
        foreach ($rows as $row){ 
            if(isset($row[$column_name]))
                $ret[] = $row[$column_name];
        }
        return $ret;
    }
    
    public function objects($class_name = false, $key = null){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if(!$class_name) $class_name = $this->default_return_class;
        $sql = $this->toSelectSql();
        $ret = array();
        Database::query($sql);
        $rows = Database::FetchAll($sql);
        $previous = null;
        foreach($rows as $index => $row){
            $object = new $class_name;
            $object->getFromArray($row);
            if($previous && $previous instanceof Core_Record){
                $previous->setNext($object->getId());
                $object->setPrev($previous->getId());
            }
            $previous = $object;
            if ($key) $ret[ $object[$key] ] = $object; else $ret[] = $object;
        }
        return $ret;
    }

    public function object($class_name = false){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        if(!$class_name) $class_name = "Core_Record";
        $sql = $this->toSelectSql();
        Database::query($sql);
        $row = Database::FetchRow();
        $object = new $class_name;
        if (is_array($row)) {
        	$object->getFromArray($row);
		}
        return $object;
    }
	
    public function fetchObject($class_name = false){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        return Database::fetchObject($class_name);
    }

    public function fetchRow(){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        return Database::fetchRow();
    }
    
    public function exec(){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        $sql = $this->toSelectSql();
        Database::query($sql);
    }
    
    public function count()
    {
    	$q = clone $this;
    	$q->select('count(*) as cnt')->limit(false)->order(false)->exec();
    	$row = Database::FetchRow();
    	return ($row) ? $row['cnt'] : 0;
	}
    
    
    public function value($simplify = false){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        return $this->row(true);
    }
    
    public function toSelectSql(){
        $params = func_get_args();
        if(!isset($this) || !($this instanceof self)) return call_user_func_array(array(self::getInstance(), __FUNCTION__), $params);
        $tables = is_array($this->tables) ? join(", ", $this->tables) : $this->tables;
        $fields = is_array($this->fields) ? join(", ", $this->fields) : $this->fields;
        //if(!$fields) $fields = "*";
        $where = is_array($this->where) ? '('.join(") AND (", $this->where).')' : $this->where;
        $ret = "select $fields from $tables";
        if($this->useindex){
            $ret .= " use index ({$this->useindex})";
        }
        if($this->leftjoin){
            $ret .= " left join {$this->leftjoin}";
        }
        if($where){
            $ret .= " where $where";
        }
        if($this->group){
            $ret .= " group by {$this->group}";
        }
        if($this->order){
            $ret .= " order by {$this->order}";
        }
        if($this->limit){
            $limit = (int)$this->limit;
            $offset = (int)$this->offset;
            $ret .= " limit $offset, $limit";
        }
        return $ret;
    }
    
    public function __toString(){
        return $this->toSelectSql();
    }
}

?>